package com.cy;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.cy.service.ConsumerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.atomic.AtomicLong;

/**
 * 当我们的主启动类使用@EnableFeignClients注解描述时,spring工程
 * 在启动时会扫描@FeignClient注解描述的接口,并基于接口创建其实现类
 * (代理类)
 */
@EnableFeignClients
@SpringBootApplication
public class ScaConsumerApplication {
    //创建日志对象
    private static final Logger log =
            LoggerFactory.getLogger(ScaConsumerApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(ScaConsumerApplication.class, args);
        //System.out.println("==System.out==");
//        log.debug("==debug==");//debug<info<warn<error
//        log.info("==info==");
//        log.warn("==warn==");
//        log.error("==error==");
    }

    /**
     * springboot 工程中可以使用此对象调用第三方服务
     */
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    /**
     * @return
     * @Bean注解由spring提供,通常用于描述方法,用于告诉spring框架 此方法的返回值要交给spring管理.类似@Controller,@Service,@Component注解(
     * 这些注解一般描述的是类)
     */
    @Bean
    @LoadBalanced
    public RestTemplate loadBalancedRestTemplate() {
        return new RestTemplate();
    }

    @RestController
    public class ConsumerController {


        @Autowired
        private ConsumerService consumerService;

        @Value("${spring.application.name}")
        private String consumerName;

        @Autowired
        private RestTemplate restTemplate;

        @Autowired
        private RestTemplate loadBalancedRestTemplate;

        //http://localhost:8090/consumer/doRestEcho01
        @GetMapping("/consumer/doRestEcho01")
        public String doRestEcho01() {
            log.debug("/consumer/doRestEcho01  {}", "doRestEcho01");
            //定义服务提供方的地址
            String url = "http://localhost:8081/provider/echo/" + consumerName;
            //调用服务提供方(sca-provider)
            return restTemplate.getForObject(url, String.class);
        }

        //LoadBalancerClient 此对象底层基于Ribbon实现负载均衡
        //LoadBalancerClient对象在服务启动时底层已经帮我们创建好了
        @Autowired
        private LoadBalancerClient loadBalancerClient;

        @GetMapping("/consumer/doRestEcho02")
        public String doRestEcho02() {
            consumerService.doConsumerService();
            //基于服务采用一定的负载均衡算法获取服务实例
            ServiceInstance choose =
                    loadBalancerClient.choose("sca-provider");
            String ip = choose.getHost();
            int port = choose.getPort();
            //定义服务提供方的地址
            //String url="http://"+ip+":"+port+"/provider/echo/"+consumerName;
            //假如不希望使用字符串拼接操作,可以使用如下方式(其中s%为占位符号,传值时一定要注意顺序)
            String url = String.format("http://%s:%s/provider/echo/%s", ip, port, consumerName);
            //调用服务提供方(sca-provider)
            return restTemplate.getForObject(url, String.class);
        }

        //创建一个可实现自增自减功能的一个对象
        private AtomicLong atomicLong = new AtomicLong(0);

        @GetMapping("/consumer/doRestEcho03")
        public String doRestEcho03() throws InterruptedException {
           /* long num=atomicLong.getAndIncrement();
            if(num%2==0) {
                Thread.sleep(200);//模拟耗时操作
                //throw new RuntimeException("...");//模拟异常比例
            }*/
            //流控规则中的链路限流
            //consumerService.doConsumerService();
            String url = String.format("http://%s/provider/echo/%s", "sca-provider", consumerName);
            //调用服务提供方(sca-provider)
            return loadBalancedRestTemplate.getForObject(url, String.class);
        }

        //http://localhost:8090/consumer/doRestEcho04?id=15 可以基于参数0,也就是id进行限流
        @GetMapping("/consumer/doRestEcho04")
        @SentinelResource
        public String doRestEcho04(Integer id, String name) {
            return String.format("request id=%d,name=%s ", id, name);
            //%d,%s为字符串中的占位符,%d一般用做数字占位符,%s为字符串占位符
        }
    }

}